from redis import RedisError
from rest_framework import filters
from rest_framework import mixins
from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import action
from rest_framework.generics import GenericAPIView, ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, \
    DestroyAPIView
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from rest_framework.permissions import AllowAny
from rest_framework.throttling import AnonRateThrottle
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet

from book.models import BookInfo
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from book.serializers import BookInfoModelSerializer


# 一级图书的列表视图
class BookInfoListViews(APIView):
    def get(self, request):
        # 获取参数
        books = BookInfo.objects.all()
        # 创建序列化
        serializer = BookInfoModelSerializer(instance=books, many=True)
        # 返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        # 获取参数
        dict_data = request.data
        # 反序列化,检验,入库
        serializer = BookInfoModelSerializer(data=dict_data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 返回响应
        return Response(serializer.data,status=status.HTTP_201_CREATED)

# 一级图书的详情视图
class BookInfoDetailViews(APIView):
    def get(self, request, pk):
        # 获取参数
        book = BookInfo.objects.get(pk=pk)
        # 序列化,检验,入库
        serializer = BookInfoModelSerializer(instance=book)
        # 返回响应
        return Response(serializer.data,status=status.HTTP_200_OK)

    def put(self, request, pk):
        # 获取参数
        book = BookInfo.objects.get(pk=pk)
        data = request.data
        # 序列化参数,检验,入库
        serializer = BookInfoModelSerializer(instance=book, data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 返回响应
        return Response(serializer.data,status=status.HTTP_200_OK)

    def delete(self,request, pk):
        # 获取参数
        book = BookInfo.objects.get(pk=pk)
        # 删除参数
        book.delete()
        # 返回响应
        return Response(status=status.HTTP_204_NO_CONTENT)


# 二级图书列表视图       二级视图的好处: 提取数据源,提取序列类出来做类属性, 调用get_queryset()  get_serializer()
class BookBookListGenericAPIViewList(GenericAPIView):
    # 将数据源抽取出来, 方便更改
    queryset = BookInfo.objects.all()
    # 将序列化抽取出来
    serializer_class = BookInfoModelSerializer

    def get(self,request):
        # 获取所有书籍
        books = self.get_queryset()   # 得到查询集,就是得到所有
        # 序列化
        serializer = self.get_serializer(instance=books,many=True)

        # 返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        # 获取修改的数据
        data = request.data
        # 反序列化,校验入库
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 返回响应
        return Response(serializer.data, status=status.HTTP_201_CREATED)

# 二级图书详情视图
class BookBookDetailGenericAPIViewList(GenericAPIView):
    # 提取查询集
    queryset = BookInfo.objects.all()
    # 提取序列化类
    serializer_class = BookInfoModelSerializer

    def get(self, request, pk):
        # 得到单个数据
        book = self.get_object()    # 根据pk获取单个对象,pk都不用传 原理看源代码
        # 序列化
        serializer = self.get_serializer(instance=book)
        # 返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    def put(self, request, pk):
        # 修改单个
        book = self.get_object()
        data = request.data
        # 序列化
        serializer = self.get_serializer(instance=book, data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    def delete(self, request, pk):
        # 删除单个
        book = self.get_object()
        book.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


# 二级视图,GenericAPIView, MiXin配合使用    三级视图好处: 继承类,可以直接返回值了,因为继承的类已经帮实现功能了
class BookBookListMixinGenericAPIViewList(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
    # 将数据源抽取出来, 方便更改
    queryset = BookInfo.objects.all()
    # 将序列化抽取出来
    serializer_class = BookInfoModelSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)

class BookBookDetailtMixinGenericAPIViewList(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, mixins.UpdateModelMixin,GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    def get(self, request, pk):
        return self.retrieve(request)

    def put(self, request, pk):
        return self.update(request)

    def delete(self, request, pk):
        return self.destroy(request)


# 6,三级视图,实现列表视图,详情视图功能         将数据源, 序列化类提出出来, 就直接可以实现功能了
class BookListThreeView(ListAPIView, CreateAPIView):
    # 1,提供通用的序列化器
    serializer_class = BookInfoModelSerializer

    # 2,提供通用的数据源
    queryset = BookInfo.objects.all()

class BookDetailThreeView(RetrieveAPIView, UpdateAPIView, DestroyAPIView):
    # 1,提供通用的序列化器
    serializer_class = BookInfoModelSerializer

    # 2,提供通用的数据源
    queryset = BookInfo.objects.all()




from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from book.serializers import BookInfoModelSerializer
from rest_framework import viewsets
from rest_framework.response import Response


# 7视图集1  viewsets.ViewSet    不用抽取数据源, 序列对象
class BookViewSet(viewsets.ViewSet):
    def list(self, request):
        # 获取所有书籍
        queryset = BookInfo.objects.all()
        # 序列化
        serializer = BookInfoModelSerializer(instance=queryset, many=True)
        # 返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    def retrieve(self, request, pk):
        queryset = BookInfo.objects.all()
        # 获取单个
        book = get_object_or_404(queryset, pk=pk)

        # 序列化
        serializer = BookInfoModelSerializer(instance=book)
        # 返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)


# 8视图集2
class BookReadOnlyViewSet(ReadOnlyModelViewSet):
    serializer_class = BookInfoModelSerializer
    queryset = BookInfo.objects.all()


# 9 模型视图集, 一次实现列表详情的增删改查
class BookModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoModelSerializer

    # 1,局部认证
    # authentication_classes = [SessionAuthentication]

    # 2,局部权限, 允许权限
    # permission_classes = [AllowAny]

    # 3,局部限流
    # throttle_classes = [AnonRateThrottle]  # 匿名的局部限流

    # 4,可选限流
    # throttle_scope = 'downloads'


    # 5,局部分页
    # pagination_class = LimitOffsetPagination  #格式: ?limit=xx 或者 ?limit=xx&offset=xx
    pagination_class = PageNumberPagination   # 格式: ?page=4 或者 ?page=4&page_size=100

    # 6,自定义分页
    # pagination_class = MyPageNumberPagination

    # 7,设置过滤字段
    # filterset_fields = ['id', 'btitle', "bread"]


    # 8 测试异常
    # def list(self, request, *args, **kwargs):
    #     # raise APIException('api异常')
    #     # raise DatabaseError('数据库大出血')
    #     raise RedisError('redis出问题了')
    #
    #     return super().list(request, *args, **kwargs)


    # 8,排序
    filter_backends = [filters.OrderingFilter]  # 用的是restframe中的,格式: ordering=字段
    # ordering_fields = ['id', 'btitle', "bread"]

    @action(methods=["get"], detail=False)   # 让自动路由生成路由
    def haha(self, request):
        # 查询阅读大于30的书籍
        book = BookInfo.objects.filter(bread__gte=999)
        # 序列化
        serializer = self.get_serializer(instance=book, many=True)
        # 返回响应
        return Response(serializer.data, status=status.HTTP_200_OK)

    @action(methods=["put"], detail=False)   # 让自动路由生成路由
    def up_data_bread(self, request, pk):
        # 更新阅读量
        data = request.data
        book = self.get_object()
        # 序列化
        serializer = self.get_serializer(instance=book, data=data, partial=True)  # partial 局部更新,必须要!
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 返回响应
        return Response(serializer.data, status=status.HTTP_201_CREATED)



class UploadView(APIView):
    throttle_scope = "uploads"
    def get(self,request):
        return Response("正在拼命....下载中...")


class MyPageNumberPagination(PageNumberPagination):
    #1,指定每页大小
    page_size = 1

    #2,可以传递参数,手动指定
    page_size_query_param = 'page_size'

    #3,设置每页最大数量
    max_page_size = 10